package moodish.server;

/**
 * Class that represents the server and handles the client's actions
 * @author hmcgf, ljgds, dbipo
 */
import java.util.HashMap;
import moodish.comm.ServerComm;
import moodish.comm.ServerSideMessage;

public class MoodishServerImpl implements MoodishServer
{
	private ServerComm				comm;
	private HashMap<String, User>	connectUsers	= new HashMap<String, User>();

	/**
	 * Method that starts the server, gets the messages from the stream and
	 * handles them according to type.
	 */
	@Override
	public void start(ServerComm serverComm)
	{
		this.comm = serverComm;
		while (true)
		{
			ServerSideMessage message = this.comm.getNextMessage();
			String usernameSource = message.getClientNickname();
			if (!isConnected(usernameSource)
					&& message.getType() != ServerSideMessage.Type.CLIENT_CONNECTED)
				comm.sendError(usernameSource, "You are not connected!");
			else
			{
				switch (message.getType())
				{
				case CLIENT_CONNECTED:
					clientConnected(usernameSource);
					break;
				case CLIENT_DISCONNECTED:
					clientDisconnected(usernameSource);
					break;
				case FRIENDSHIP:
					createFriendship(usernameSource, message.getPayload());
					break;
				case MOODISH_MESSAGE:
					sendMoodToFriends(usernameSource, message.getPayload());
					break;
				case UNFRIENDSHIP:
					destroyFriendship(usernameSource, message.getPayload());
					break;
				default:
					break;
				}
			}

		}
	}

	/**
	 * Method that checks if a given user is online
	 * 
	 * @param username
	 * @return boolean connectUsers.containsKey(username)
	 */
	private boolean isConnected(String username)
	{
		return connectUsers.containsKey(username);
	}

	/**
	 * Method used to "unfriend" two users
	 * 
	 * @param usernameSource
	 * @param usernameUnfriend
	 */
	private void destroyFriendship(String usernameSource, String usernameUnfriend)
	{
		User user = connectUsers.get(usernameSource);
		User unFriend = connectUsers.get(usernameUnfriend);
		if (user.isFriend(usernameUnfriend))
		{
			user.unfriend(usernameUnfriend);
			unFriend.unfriend(usernameSource);
			comm.sendNewUnfriendship(usernameUnfriend, usernameSource);
		}
		else
		{
			comm.sendError(usernameSource, usernameUnfriend
					+ " is not your friend!");
		}
		
	}

	/**
	 * Method used to send "Mood" to friends
	 * 
	 * @param usernameSource
	 * @param mood
	 */
	private void sendMoodToFriends(String usernameSource, String mood)
	{
		User user = connectUsers.get(usernameSource);
		user.setMood(mood);
		for (User friend : user.getFriends())
		{
			comm.sendMoodishMessage(user.getUsername(), friend.getUsername(),
					mood);
		}
	}

	/**
	 * Method used to "friend" two users
	 * 
	 * @param usernameSource
	 * @param usernameNewFriend
	 */
	private void createFriendship(String usernameSource,
			String usernameNewFriend)
	{
		if (isConnected(usernameNewFriend))
		{
			if (!usernameSource.equals(usernameNewFriend))
			{
				if (connectUsers.get(usernameSource).isFriend(usernameNewFriend))
				{
					comm.sendError(usernameSource, usernameNewFriend
							+ " is already friends with you!");
				}
				else
				{
					User userSource = connectUsers.get(usernameSource);
					User userTarget = connectUsers.get(usernameNewFriend);
					userSource.friend(userTarget);
					userTarget.friend(userSource);
					comm.sendNewFriendship(userTarget.getUsername(),
							userSource.getUsername());
					if (userSource.getMood()!="")
					{
						comm.sendMoodishMessage(usernameSource, usernameNewFriend, userSource.getMood());
					}
					
					if (userTarget.getMood()!="")
					{
						comm.sendMoodishMessage(usernameNewFriend, usernameSource, userTarget.getMood());
					}
					
				}
			}
			else
			{
				comm.sendError(usernameSource, usernameNewFriend
						+ " you can't be friend of yourself!");
			}
			
		}
		else
			comm.sendError(usernameSource, usernameNewFriend
					+ " not connected, can't be friends!");

	}

	/**
	 * Method used to Disconnect a user
	 * 
	 * @param username
	 */
	private void clientDisconnected(String username)
	{
		System.out.println(username);
		for (User u : connectUsers.values())
		{
			if (!u.getUsername().equals(username))
				comm.sendClientDisconnected(u.getUsername(), username);
		}
		connectUsers.remove(username);
		removeFriendshipFromConnectedClients(username);
	}

	/**
	 * Auxiliary Method used to wipe the disconnected user from other users
	 * "friend" list
	 * 
	 * @param username
	 */
	private void removeFriendshipFromConnectedClients(String username)
	{
		for (User u : connectUsers.values())
			u.unfriend(username);
	}

	/**
	 * Method used to connect a new user, upon login a message is sent to every
	 * user saying that the new user has logged in and returns the users that
	 * are currently connected
	 * 
	 * @param username
	 */
	private void clientConnected(String username)
	{
		if (connectUsers.containsKey(username))
		return;
		
			connectUsers.put(username, new User(username));
			comm.sendClientConnected(username, "");
			for (User u : connectUsers.values())
			{
				comm.sendClientConnected(u.getUsername(), username);
				comm.sendClientConnected(username, u.getUsername());
			}
			
		}
	}
